package laxproxy

import (
	"encoding/binary"
	"laxkits/lib/laxutils"
)

type (
	//  协议头需要支持调用的接口
	IHookHeader interface {
		// 协议id
		GetProtoId() uint32
		// 协议长度
		GetBodyLen() uint32
		// 是否有压缩
		HasCompress() bool
		// 包头长度
		GetHeadLen() int
	}
	// 默认支持的协议包头方式
	DefaultHookHeader struct {
		// 协议内容长度
		MsgBodyLen uint32
		// 协议id
		ProtoId uint32
		// 包头长度
		HeadLen int
	}
)

func (h *DefaultHookHeader) GetProtoId() uint32 { return h.ProtoId }
func (h *DefaultHookHeader) GetBodyLen() uint32 { return h.MsgBodyLen }
func (h *DefaultHookHeader) HasCompress() bool  { return false }
func (h *DefaultHookHeader) GetHeadLen() int    { return h.HeadLen }

type (
	// 解包组包器
	IHookCodec interface {
		// 解码包头,需要用户实现
		DecodeHead(buf []byte) (IHookHeader, error)
		// 组合消息,需要用户实现
		TryEncode(header IHookHeader, msgBody []byte) ([]byte, error)
		// 解压消息体
		TryDecompress(header IHookHeader, msgBody []byte) []byte
		// 压缩消息体
		TryCompress(header IHookHeader, msgBody []byte) []byte
		// 计算下一条消息长度
		CalcNextMsgLen(buf []byte) uint32
		// 收到消息的处理, codec才是原版的codec
		OnMessage(codec IHookCodec, buf []byte, userCtx IProxyUserContext, toServer bool) []byte
		// 打印消息
		PrintMessage(userCtx IProxyUserContext, header IHookHeader, msgBody []byte, toServer bool)
		/// 根据协议id和协议消息体组装消息
		TryBuildWholeMsg(protoId uint32, isRpc bool, msgBody []byte) []byte
	}
	// 默认的coder,实现是不需要全部重写
	DefaultHookCodec struct{}
)

func (c *DefaultHookCodec) DecodeHead(buf []byte) (IHookHeader, error) { panic("Not Implement.") }
func (c *DefaultHookCodec) TryEncode(header IHookHeader, msgBody []byte) ([]byte, error) {
	panic("Not Implement.")
}
func (c *DefaultHookCodec) TryBuildWholeMsg(protoId uint32, msgBody []byte) []byte {
	panic("Not Implement.")
}
func (c *DefaultHookCodec) PrintMessage(header IHookHeader, toServer bool) {}

func (c *DefaultHookCodec) TryDecompress(header IHookHeader, msgBody []byte) []byte {
	if header.HasCompress() {
		return laxutils.ZlibDecompress(msgBody)
	}
	return msgBody
}

func (c *DefaultHookCodec) TryCompress(header IHookHeader, msgBody []byte) []byte {
	if header.HasCompress() {
		return laxutils.ZlibCompress(msgBody)
	}
	return msgBody
}

func (c *DefaultHookCodec) CalcNextMsgLen(buf []byte) uint32 {
	if len(buf) < 4 {
		return 0
	}
	return binary.LittleEndian.Uint32(buf[:4]) + 4
}

func (c *DefaultHookCodec) OnMessage(codec IHookCodec, buf []byte, userCtx IProxyUserContext, toServer bool) []byte {
	if head, err := codec.DecodeHead(buf); err == nil {
		msgBody := codec.TryDecompress(head, buf[head.GetHeadLen():])
		codec.PrintMessage(userCtx, head, msgBody, toServer)
		if parser := TryGetProtocolParser(head.GetProtoId()); parser != nil {
			if toServer {
				msgBody = (*parser).Client2Server(msgBody, userCtx)
			} else {
				msgBody = (*parser).Server2Client(msgBody, userCtx)
			}
			msgBody = codec.TryCompress(head, msgBody)
			if finalMsg, err := codec.TryEncode(head, msgBody); err == nil {
				return finalMsg
			}
		}
	}
	return buf
}
